// handlers/pages.go
// Contains handlers for project pages, canvas messages, and prompt history.

package handlers

import (
	"database/sql"
	"net/http"
	"regexp"
	"strings"

	"github.com/gin-gonic/gin"

	"agentdesign/models"
)

// ListProjectPages returns the pages for a given project.
func (h *Handler) ListProjectPages(c *gin.Context) {
	projectID := c.Params.ByName("id")
	pages, err := h.service.ListProjectPages(projectID)

	result := Result[[]models.ProjectPage]{
		Code: http.StatusOK,
		Data: pages,
		Msg:  ResponseMessage.SUCCESS,
	}

	if err != nil {
		result.Code = http.StatusInternalServerError
		result.Msg = err.Error()
	}

	c.JSON(result.Code, result)
}

// CreateProjectPageRequest describes the payload for creating a page.
type CreateProjectPageRequest struct {
	Slug        string `json:"slug"`
	Name        string `json:"name" binding:"required"`
	Summary     string `json:"summary"`
	Status      string `json:"status"`
	Device      string `json:"device" binding:"required"`
	ScreenCount int    `json:"screenCount"`
	Thumbnail   string `json:"thumbnail"`
}

// CreateProjectPage creates a page under the specified project.
func (h *Handler) CreateProjectPage(c *gin.Context) {
	projectID := c.Params.ByName("id")
	var req CreateProjectPageRequest

	result := Result[models.ProjectPage]{
		Code: http.StatusCreated,
		Data: models.ProjectPage{},
		Msg:  ResponseMessage.SUCCESS,
	}

	if err := c.ShouldBindJSON(&req); err != nil {
		result.Code = http.StatusBadRequest
		result.Msg = err.Error()
		c.JSON(result.Code, result)

		return
	}

	slug := strings.TrimSpace(req.Slug)
	if slug == "" {
		slug = generateSlug(req.Name)
	}

	page, err := h.service.CreateProjectPage(models.ProjectPage{
		ProjectID:   projectID,
		Slug:        slug,
		Name:        req.Name,
		Summary:     req.Summary,
		Status:      req.Status,
		Device:      req.Device,
		ScreenCount: req.ScreenCount,
		Thumbnail:   req.Thumbnail,
	})
	if err != nil {
		result.Code = http.StatusInternalServerError
		result.Msg = err.Error()
		c.JSON(result.Code, result)

		return
	}

	result.Data = page

	c.JSON(result.Code, result)
}

// GetProjectPage returns a specific page for a project.
func (h *Handler) GetProjectPage(c *gin.Context) {
	projectID := c.Params.ByName("projectId")
	pageID := c.Params.ByName("pageId")

	page, err := h.service.GetProjectPage(projectID, pageID)
	result := Result[models.ProjectPage]{
		Code: http.StatusOK,
		Data: page,
		Msg:  ResponseMessage.SUCCESS,
	}

	if err != nil {
		if err == sql.ErrNoRows {
			result.Code = http.StatusNotFound
			result.Msg = "page not found"
		} else {
			result.Code = http.StatusInternalServerError
			result.Msg = err.Error()
		}
	}

	c.JSON(result.Code, result)
}

// UpdateProjectPageRequest mirrors the editable fields for a page.
type UpdateProjectPageRequest struct {
	Name             string `json:"name" binding:"required"`
	Summary          string `json:"summary"`
	Status           string `json:"status"`
	Device           string `json:"device" binding:"required"`
	ScreenCount      int    `json:"screenCount"`
	Thumbnail        string `json:"thumbnail"`
	CurrentVersionID string `json:"currentVersionId"`
}

// UpdateProjectPage applies edits to an existing page.
func (h *Handler) UpdateProjectPage(c *gin.Context) {
	projectID := c.Params.ByName("projectId")
	pageID := c.Params.ByName("pageId")
	var req UpdateProjectPageRequest

	result := Result[bool]{
		Code: http.StatusOK,
		Data: false,
		Msg:  ResponseMessage.SUCCESS,
	}

	if err := c.ShouldBindJSON(&req); err != nil {
		result.Code = http.StatusBadRequest
		result.Msg = err.Error()
		c.JSON(result.Code, result)

		return
	}

	rows, err := h.service.UpdateProjectPage(models.ProjectPage{
		ID:               pageID,
		ProjectID:        projectID,
		Name:             req.Name,
		Summary:          req.Summary,
		Status:           req.Status,
		Device:           req.Device,
		ScreenCount:      req.ScreenCount,
		Thumbnail:        req.Thumbnail,
		CurrentVersionID: req.CurrentVersionID,
	})

	if err != nil {
		result.Code = http.StatusInternalServerError
		result.Msg = err.Error()
		c.JSON(result.Code, result)

		return
	}

	result.Data = rows > 0

	c.JSON(result.Code, result)
}

// DeleteProjectPage removes a page from the project.
func (h *Handler) DeleteProjectPage(c *gin.Context) {
	projectID := c.Params.ByName("projectId")
	pageID := c.Params.ByName("pageId")

	result := Result[bool]{
		Code: http.StatusOK,
		Data: false,
		Msg:  ResponseMessage.SUCCESS,
	}

	rows, err := h.service.DeleteProjectPage(projectID, pageID)
	if err != nil {
		result.Code = http.StatusInternalServerError
		result.Msg = err.Error()
		c.JSON(result.Code, result)

		return
	}

	if rows == 0 {
		result.Code = http.StatusNotFound
		result.Msg = "page not found"
		c.JSON(result.Code, result)

		return
	}

	result.Data = true

	c.JSON(result.Code, result)
}

var slugSanitizer = regexp.MustCompile(`[^a-z0-9]+`)

// generateSlug creates a URL-safe identifier derived from the provided text.
func generateSlug(text string) string {
	base := strings.ToLower(strings.TrimSpace(text))
	if base == "" {
		base = "page"
	}

	base = slugSanitizer.ReplaceAllString(base, "-")
	base = strings.Trim(base, "-")

	if base == "" {
		base = "page"
	}

	return base
}
